001 /* 002 * Copyright 2004-2005 Stephen J. McConnell. 003 * Copyright 2004 Niclas Hedhman 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 013 * implied. 014 * 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package net.dpml.transit.artifact; 020 021 import java.io.IOException; 022 import java.io.PrintWriter; 023 024 import java.net.URL; 025 import java.net.URLConnection; 026 import java.net.URLStreamHandler; 027 import java.security.AccessController; 028 import java.security.PrivilegedAction; 029 030 import net.dpml.transit.Transit; 031 import net.dpml.transit.TransitRuntimeException; 032 import net.dpml.transit.SecuredTransitContext; 033 034 /** 035 * The artifact URL protocol handler. 036 * @author <a href="http://www.dpml.net">The Digital Product Meta Library</a> 037 * @version 1.0.0 038 */ 039 public class Handler extends URLStreamHandler 040 { 041 // ------------------------------------------------------------------------ 042 // static 043 // ------------------------------------------------------------------------ 044 045 /** 046 * Default buffer size. 047 */ 048 private static final int BUFFER_SIZE = 100; 049 050 // ------------------------------------------------------------------------ 051 // state 052 // ------------------------------------------------------------------------ 053 054 /** 055 * The transit context. 056 */ 057 private SecuredTransitContext m_context; 058 059 // ------------------------------------------------------------------------ 060 // constructor 061 // ------------------------------------------------------------------------ 062 063 /** 064 * Creation of a new transit artifact protocol handler. 065 */ 066 public Handler() 067 { 068 try 069 { 070 Transit.getInstance(); 071 m_context = SecuredTransitContext.getInstance(); 072 } 073 catch( RuntimeException e ) 074 { 075 e.printStackTrace(); 076 throw e; 077 } 078 } 079 080 // ------------------------------------------------------------------------ 081 // implementation 082 // ------------------------------------------------------------------------ 083 084 /** 085 * Opens a connection to the specified URL. 086 * 087 * @param url A URL to open a connection to. 088 * @return The established connection. 089 * @throws IOException If a connection failure occurs. 090 */ 091 protected URLConnection openConnection( final URL url ) 092 throws IOException 093 { 094 return new ArtifactURLConnection( url, m_context ); 095 } 096 097 /** 098 * Return the external representation of the supplied url. 099 * @param u the url 100 * @return a string representing of the url as an artifact uri 101 */ 102 protected String toExternalForm( URL u ) 103 { 104 StringBuffer buf = new StringBuffer( BUFFER_SIZE ); 105 buf.append( u.getProtocol() ); 106 buf.append( ":" ); 107 String path = getRealPath( u ); 108 if( path != null ) 109 { 110 int lastPos = path.length() - 1; 111 if( path.charAt( lastPos ) == '/' ) 112 { 113 buf.append( path.substring( 0, lastPos ) ); 114 } 115 else 116 { 117 buf.append( path ); 118 } 119 } 120 121 String internal = getInternalPath( u ); 122 if( null != internal ) 123 { 124 buf.append( internal ); 125 } 126 127 String version = u.getUserInfo(); 128 if( ( version != null ) && !"".equals( version ) ) 129 { 130 buf.append( '#' ); 131 buf.append( version ); 132 } 133 String result = buf.toString(); 134 buf.setLength( 0 ); 135 return result; 136 } 137 138 /** 139 * Return the pure artifact path without any internal address. 140 * @param url the url to evaluate 141 * @return the pure path 142 */ 143 private String getRealPath( URL url ) 144 { 145 String path = url.getPath(); 146 if( null == path ) 147 { 148 return null; 149 } 150 int index = path.indexOf( "!" ); 151 if( index < 0 ) 152 { 153 return path; 154 } 155 else 156 { 157 return path.substring( 0, index ); 158 } 159 } 160 161 /** 162 * Return the value of an internal address associated with a path. 163 * @param url the url to evaluate 164 * @return the internal address of null if the url does not contain an internal address 165 */ 166 private String getInternalPath( URL url ) 167 { 168 String path = url.getPath(); 169 if( null == path ) 170 { 171 return null; 172 } 173 int index = path.indexOf( "!" ); 174 if( index < 0 ) 175 { 176 return null; 177 } 178 else 179 { 180 return path.substring( index ); 181 } 182 } 183 184 185 /** 186 * Parse the supplied specification. 187 * @param dest the destination url to populate 188 * @param spec the supplied spec 189 * @param start the starting position 190 * @param limit the limit 191 */ 192 protected void parseURL( final URL dest, String spec, int start, int limit ) 193 { 194 try 195 { 196 final String protocol = dest.getProtocol(); 197 String specPath = spec.substring( start, limit ); 198 String path = dest.getPath(); 199 200 if( path == null ) 201 { 202 path = specPath; 203 if( !path.endsWith( "/" ) && ( path.indexOf( "!" ) < 0 ) ) 204 { 205 path = path + "/"; 206 } 207 } 208 else 209 { 210 int lastPos = path.length() - 1; 211 if( path.charAt( lastPos ) == '/' ) 212 { 213 path = path.substring( 0, lastPos ); 214 } 215 if( specPath.charAt( 0 ) == '/' ) 216 { 217 path = path + "!" + specPath; 218 } 219 else 220 { 221 path = path + "!/" + specPath; 222 } 223 } 224 String version = dest.getUserInfo(); 225 if( version == null ) 226 { 227 if( limit < spec.length() ) 228 { 229 version = spec.substring( limit + 1 ); 230 } 231 } 232 final String user = version; 233 final String authority = null; 234 final int port = -1; 235 final String host = null; 236 final String query = null; 237 final String ref = null; 238 final String finalPath = path; 239 AccessController.doPrivileged( 240 new PrivilegedAction() 241 { 242 public Object run() 243 { 244 setURL( dest, protocol, host, port, authority, user, finalPath, query, ref ); 245 return null; 246 } 247 } 248 ); 249 } 250 catch( Throwable e ) 251 { 252 try 253 { 254 PrintWriter log = Transit.getInstance().getLogWriter(); 255 String message = "Unable to parse the URL: " 256 + dest + ", " + spec + ", " + start + ", " + limit; 257 log.println( message ); 258 log.println( "---------------------------------------------------" ); 259 e.printStackTrace( log ); 260 } 261 catch( TransitRuntimeException f ) 262 { 263 // Panic!!!! Should not happen. 264 f.printStackTrace(); 265 e.printStackTrace(); 266 } 267 } 268 } 269 }